!> author: 左志华
!> date: 2022-07-02
!> license: BSD 3-Clause
!>
!> External forces <br>
!> 外力：1. 重力；2. 边界排斥力。
module sph_external_force

    use sph_kinds, only: rk
    use sph_math, only: get_distance, g
    use sph_particle, only: particle_t
    use sph_env, only: nums
    use twin_sph_list_type, only: twin_list_t

    logical :: gravity  !! Gravity on/off <br>
                        !! 是否有重力
    real(rk) :: r0      !! External force radius <br>
                        !! 排斥力半径
    real(rk) :: dd      !! v_{max}^2
                        !! 速度最大值的平方量级
    procedure(external_force_fcn), pointer :: external_force => external_force_with_gravity
                                                                        !! External force function pointer <br>
                                                                        !! 外力函数指针

    integer, parameter :: p1 = 12, p2 = 4   !! p1, p2 are used to calculate the boundary repulsion <br>
                                            !! p1, p2 用来计算边界排斥力
    abstract interface

        !> Solve the external force <br>
        !> 外力求解，涉及重力和边界力
        subroutine external_force_fcn(particle, pairs, acc)
            import :: particle_t, twin_list_t, rk
            type(particle_t), intent(in) :: particle    !! particle <br>
                                                    !! 区域
            type(twin_list_t), intent(in) :: pairs  !! Pairs <br>
                                                    !! 粒子对
            real(rk), intent(inout) :: acc(:, :)    !! Acceleration <br>
                                                    !! 加速度
        end subroutine external_force_fcn

    end interface

contains

    !> Solve the external force with gravity <br>
    !> 含重力的外力
    pure subroutine external_force_with_gravity(particle, pairs, acc)
        type(particle_t), intent(in) :: particle    !! particle <br>
                                                !! 区域
        type(twin_list_t), intent(in) :: pairs  !! Pairs <br>
                                                !! 粒子对
        real(rk), intent(inout) :: acc(:, :)    !! Acceleration <br>
                                                !! 加速度 \( F_{external} = -g + F_{boundary} \)
        integer :: i
        real(rk) :: dx(2), r

        ! -------------------------------- 计算重力 --------------------------------- !
        acc(2, :nums(1)) = acc(2, :nums(1)) - g   ! 仅对实体粒子起作用，虚粒子不需要求解加速度而运动

        ! ----------------------------- 计算边界排斥力 ------------------------------- !
        include "boundary_repulsion.finc"
    end subroutine external_force_with_gravity

    !> Solve the external force without gravity <br>
    !> 无重力的外力
    pure subroutine external_force_without_gravity(particle, pairs, acc)
        type(particle_t), intent(in) :: particle    !! particle <br>
                                                !! 区域
        type(twin_list_t), intent(in) :: pairs  !! Pairs <br>
                                                !! 粒子对
        real(rk), intent(inout) :: acc(:, :)    !! Acceleration <br>
                                                !! 加速度 \[ F_{external} = F_{boundary}\]
        integer :: i
        real(rk) :: dx(2), r

        ! ----------------------------- 计算边界排斥力 ------------------------------- !
        include "boundary_repulsion.finc"
    end subroutine external_force_without_gravity

end module sph_external_force
